package net.pws.common.security;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.pws.common.beanutils.ConvertUtils;
import net.pws.common.security.filter.FilterInvocation;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * Web工具类，提供了访问Web上下文的助手方法
 * 
 * @author dz
 */
public abstract class WebUtils {
    
    protected static final Log logger = LogFactory.getLog(WebUtils.class);
    
    static interface ParameterFilter {
        
        public boolean includePrefix();
        
        public String filterPrefix(String name);
        
        public boolean matches(String parameterName);
        
    }
    
    /**
     * 提取HttpServletRequest中所有的参数（来自http请求）值对并转化为Map
     * 
     * @param request
     * @return
     */
    public static Map<String,Object> convertRequestParameters2Map(final HttpServletRequest request,
                                                                  final String prefix,
                                                                  final boolean includePrefix) {
        return convertRequestParameters2Map(request, new ParameterFilter() {
            
            public boolean includePrefix() {
                return includePrefix;
            }
            
            public String filterPrefix(String name) {
                if (name.startsWith(prefix)) {
                    return name.substring(prefix.length());
                }
                return name;
            }
            
            public boolean matches(String parameterName) {
                return parameterName.startsWith(prefix);
            }
            
        });
    }
    
    /**
     * 提取HttpServletRequest中所有的参数（来自http请求）值对并转化为Map
     * 
     * @param request
     * @return
     */
    public static Map<String,Object> convertRequestParameters2Map(final HttpServletRequest request,
                                                                  final ParameterFilter filter) {
        Map<String,Object> result = new HashMap<String,Object>();
        Enumeration<String> paramNames = request.getParameterNames();
        while (paramNames.hasMoreElements()) {
            String paramName = paramNames.nextElement();
            if ((filter != null) && !filter.matches(paramName)) {
                continue;
            }
            String[] paramValue = request.getParameterValues(paramName);
            
            if (!filter.includePrefix()) {
                paramName = filter.filterPrefix(paramName);
            }
            
            if (paramValue.length == 0) {
                result.put(paramName, null);
            }
            else if (paramValue.length == 1) {
                result.put(paramName, paramValue[0]);
            }
            else {
                result.put(paramName, paramValue);
            }
        }
        return result;
    }
    
    public static String[] getStringArrayByParameter(HttpServletRequest request,
                                                     String parameterName,
                                                     String character4Split) {
        String parameter = request.getParameter(parameterName);
        return StringUtils.isEmpty(parameter) ? new String[0]
                                             : parameter.split(character4Split);
    }
    
    public static Long[] getLongArrayByParameter(HttpServletRequest request,
                                                 String parameterName,
                                                 String character4Split) {
        String[] split = getStringArrayByParameter(request,
                                                   parameterName,
                                                   character4Split);
        List longs = new ArrayList();
        for (int i = 0; i < split.length; i++) {
            String string = split[i];
            if (NumberUtils.isNumber(string)) {
                NumberUtils.toLong(string);
                longs.add(NumberUtils.toLong(string));
            }
        }
        return (Long[]) longs.toArray(new Long[longs.size()]);
    }
    
    // ********************渲染输出结果的展现界面*******************
    /**
     * 直接输出.
     * 
     * @param contentType
     *            内容的类型.html,text,xml,json,excel,word的值见后
     */
    public static void render(HttpServletResponse response,
                              String text,
                              String contentType) {
        try {
            response.setContentType(contentType);
            response.getWriter().print(text);
            response.getWriter().flush();
        }
        catch (IOException e) {
            logger.error(e, e);
        }
    }
    
    /**
     * 直接输出J-SON代码.在B/S之间直接传递JSON代码是Ajax中一种比较实效的用法,JSON的定义如{name:"Tom",age:20}
     */
    public static void renderJson(HttpServletResponse response, String text) {
        render(response, text, "text/x-json;charset=UTF-8");
    }
    
    /**
     * 直接输出纯文本.
     */
    public static void renderText(HttpServletResponse response, String text) {
        render(response, text, "text/plain;charset=UTF-8");
    }
    
    /**
     * 直接输出HTML.
     */
    public static void renderHtml(HttpServletResponse response, String text) {
        render(response, text, "text/html;charset=UTF-8");
    }
    
    /**
     * 直接输出XML.
     */
    public static void renderXML(HttpServletResponse response, String text) {
        render(response, text, "text/xml;charset=UTF-8");
    }
    
    /**
     * 直接输出Excel.
     */
    public static void renderExcel(HttpServletResponse response, String text) {
        render(response, text, "application/vnd.ms-excel;charset=UTF-8");
    }
    
    /**
     * 直接输出Word.
     */
    public static void renderWord(HttpServletResponse response, String text) {
        render(response, text, "application/vnd.ms-word;charset=UTF-8");
    }
    
    /**
     * 直接输出Pdf.
     */
    public static void renderPdf(HttpServletResponse response, String text) {
        render(response, text, "application/pdf;charset=UTF-8");
    }
    
    /**
     * 用戶的http请求的方法是否是GET
     * 
     * @param request
     * @return
     */
    public static boolean isGet(HttpServletRequest request) {
        return "GET".equalsIgnoreCase(request.getMethod());
    }
    
    /**
     * 用戶的http请求的方法是否是POST
     * 
     * @param request
     * @return
     */
    public static boolean isPost(HttpServletRequest request) {
        return "POST".equalsIgnoreCase(request.getMethod());
    }
    
    /**
     * 获取指定的参数值，并转化为Long类型
     * 
     * @param request
     * @param parameterName
     * @return
     */
    public static Long getLongParameter(HttpServletRequest request,
                                        String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        String value = request.getParameter(parameterName);
        return ConvertUtils.convertString2Long(value);
    }
    
    /**
     * 获取指定的参数值，并转化为BigDecimal类型
     * 
     * @param request
     * @param parameterName
     * @return
     */
    public static BigDecimal getBigDecimalParameter(HttpServletRequest request,
                                                    String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        String value = request.getParameter(parameterName);
        return ConvertUtils.convertString2BigDecimal(value);
    }
    
    /**
     * 获取指定的参数值，并转化为Integer类型
     * 
     * @param request
     * @param parameterName
     * @return
     */
    public static Integer getIntegerParameter(HttpServletRequest request,
                                              String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        String value = request.getParameter(parameterName);
        return ConvertUtils.convertString2Integer(value);
    }
    
    /**
     * 获取指定的参数值，并转化为Integer类型
     * 
     * @param request
     * @param parameterName
     * @return
     */
    public static Boolean getBooleanParameter(HttpServletRequest request,
                                              String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        String value = request.getParameter(parameterName);
        return ConvertUtils.convertString2Boolean(value);
    }
    
    /**
     * 获取指定的参数值，返回对应的String
     * 
     * @param request
     * @param parameterName
     * @return
     */
    public static String getStringParameter(HttpServletRequest request,
                                            String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        return request.getParameter(parameterName);
    }
    
    /**
     * 获取指定的参数值，如果对应的值不存在或者为空，则返回缺省值
     * 
     * @param request
     * @param parameterName
     * @param defaultValue
     * @return
     */
    public static String getStringParameter(HttpServletRequest request,
                                            String parameterName,
                                            String defaultValue) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        String result = request.getParameter(parameterName);
        return (StringUtils.isNotEmpty(result)) ? result : defaultValue;
    }
    
    /**
     * 获取指定的参数值，并转化为Long类型
     * 
     * @param config
     * @param parameterName
     * @return
     */
    public static Long getLongParameter(ServletConfig config,
                                        String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        String value = config.getInitParameter(parameterName);
        return ConvertUtils.convertString2Long(value);
    }
    
    /**
     * 获取指定的参数值，并转化为Integer类型
     * 
     * @param config
     * @param parameterName
     * @return
     */
    public static Integer getIntegerParameter(ServletConfig config,
                                              String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        String value = config.getInitParameter(parameterName);
        return ConvertUtils.convertString2Integer(value);
    }
    
    /**
     * 获取指定的参数值，并转化为Boolean类型
     * 
     * @param config
     * @param parameterName
     * @return
     */
    public static Boolean getBooleanParameter(ServletConfig config,
                                              String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        String value = config.getInitParameter(parameterName);
        return ConvertUtils.convertString2Boolean(value);
    }
    
    /**
     * 获取指定的参数值，返回对应的String
     * 
     * @param config
     * @param parameterName
     * @return
     */
    public static String getStringParameter(ServletConfig config,
                                            String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        return config.getInitParameter(parameterName);
    }
    
    /**
     * 获取指定的参数值，如果对应的值不存在或者为空，则返回缺省值
     * 
     * @param config
     * @param parameterName
     * @param defaultValue
     * @return
     */
    public static String getStringParameter(ServletConfig config,
                                            String parameterName,
                                            String defaultValue) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        String result = config.getInitParameter(parameterName);
        return (StringUtils.isNotEmpty(result)) ? result : defaultValue;
    }
    
    /**
     * 获取指定的参数值，并转化为Long类型
     * 
     * @param context
     * @param parameterName
     * @return
     */
    public static Long getLongAttribute(ServletContext context,
                                        String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        return ConvertUtils.convertObject2Long(context.getAttribute(parameterName));
    }
    
    /**
     * 获取指定的参数值，并转化为Long类型
     * 
     * @param context
     * @param parameterName
     * @return
     */
    public static Long getLongAttribute(ServletContext context,
                                        String parameterName,
                                        Long defaultValue) {
        try {
            Long result = getLongAttribute(context, parameterName);
            return (null != result) ? result : defaultValue;
        }
        catch (RuntimeException e) {
            return defaultValue;
        }
    }
    
    /**
     * 获取指定的参数值，并转化为Integer类型
     * 
     * @param context
     * @param parameterName
     * @return
     */
    public static Integer getIntegerAttribute(ServletContext context,
                                              String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        return ConvertUtils.convertObject2Integer(context.getAttribute(parameterName));
    }
    
    /**
     * 获取指定的参数值，并转化为Integer类型
     * 
     * @param context
     * @param parameterName
     * @return
     */
    public static Integer getIntegerAttribute(ServletContext context,
                                              String parameterName,
                                              Integer defaultValue) {
        try {
            Integer result = getIntegerAttribute(context, parameterName);
            return (null != result) ? result : defaultValue;
        }
        catch (RuntimeException e) {
            return defaultValue;
        }
    }
    
    /**
     * 获取指定的参数值，并转化为Integer类型
     * 
     * @param context
     * @param parameterName
     * @return
     */
    public static Boolean getBooleanAttribute(ServletContext context,
                                              String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        return ConvertUtils.convertObject2Boolean(context.getAttribute(parameterName));
    }
    
    /**
     * 获取指定的参数值，并转化为Integer类型
     * 
     * @param context
     * @param parameterName
     * @return
     */
    public static Boolean getBooleanAttribute(ServletContext context,
                                              String parameterName,
                                              Boolean defaultValue) {
        try {
            Boolean result = getBooleanAttribute(context, parameterName);
            return (null != result) ? result : defaultValue;
        }
        catch (RuntimeException e) {
            return defaultValue;
        }
    }
    
    /**
     * 获取指定的参数值，返回对应的String
     * 
     * @param context
     * @param parameterName
     * @return
     */
    public static String getStringAttribute(ServletContext context,
                                            String parameterName) {
        if (StringUtils.isEmpty(parameterName)) {
            throw new IllegalArgumentException();
        }
        return ConvertUtils.convertObject2String(context.getAttribute(parameterName));
    }
    
    /**
     * 获取指定的参数值，如果对应的值不存在或者为空，则返回缺省值
     * 
     * @param context
     * @param parameterName
     * @param defaultValue
     * @return
     */
    public static String getStringAttribute(ServletContext context,
                                            String parameterName,
                                            String defaultValue) {
        String result = getStringAttribute(context, parameterName);
        return (StringUtils.isNotEmpty(result)) ? result : defaultValue;
    }
    
    /**
     * Web应用的WEB-INF目录的全路径
     * 
     * @param servletContext
     * @return
     */
    public static String getWebInfPath(ServletContext servletContext) {
        return servletContext.getRealPath("/WEB-INF");
    }
    
    /**
     * 统一返回json对象时的结果模板 目的方便页面统一处理
     * 
     * @param resultType
     * @param message
     * @param data
     * @return
     */
    public static String genernateJsonResult(String resultType,
                                             String message,
                                             String data) {
        StringBuffer result = new StringBuffer();
        result.append("{\"resultType\":\"").append(resultType).append("\"");
        if (StringUtils.isNotEmpty(message)) {
            result.append(",\"message\":\"").append(message).append("\"");
        }
        if (StringUtils.isNotEmpty(data)) {
            result.append(",\"data\":\"").append(data).append("\"");
        }
        result.append("}");
        return result.toString();
    }
    
    /**
     * Obtains the full URL the client used to make the request.
     * <p>
     * Note that the server port will not be shown if it is the default server port for HTTP or
     * HTTPS (ie 80 and 443 respectively).
     * </p>
     * 
     * @return the full URL
     */
    private static String buildFullRequestUrl(String scheme,
                                              String serverName,
                                              int serverPort,
                                              String contextPath,
                                              String requestUrl,
                                              String servletPath,
                                              String requestURI,
                                              String pathInfo,
                                              String queryString) {
        
        boolean includePort = true;
        
        if ("http".equals(scheme.toLowerCase()) && (serverPort == 80)) {
            includePort = false;
        }
        
        if ("https".equals(scheme.toLowerCase()) && (serverPort == 443)) {
            includePort = false;
        }
        
        return scheme + "://"
               + serverName
               + ((includePort) ? (":" + serverPort) : "")
               + contextPath
               + buildRequestUrl(servletPath,
                                 requestURI,
                                 contextPath,
                                 pathInfo,
                                 queryString);
    }
    
    /**
     * Obtains the web application-specific fragment of the URL.
     * 
     * @return the URL, excluding any server name, context path or servlet path
     */
    private static String buildRequestUrl(String servletPath,
                                          String requestURI,
                                          String contextPath,
                                          String pathInfo,
                                          String queryString) {
        
        String uri = servletPath;
        
        if (uri == null) {
            uri = requestURI;
            uri = uri.substring(contextPath.length());
        }
        
        return uri + ((pathInfo == null) ? "" : pathInfo)
               + ((queryString == null) ? "" : ("?" + queryString));
    }
    
    public static String getFullRequestUrl(FilterInvocation fi) {
        HttpServletRequest r = fi.getHttpRequest();
        
        return buildFullRequestUrl(r.getScheme(),
                                   r.getServerName(),
                                   r.getServerPort(),
                                   r.getContextPath(),
                                   r.getRequestURL().toString(),
                                   r.getServletPath(),
                                   r.getRequestURI(),
                                   r.getPathInfo(),
                                   r.getQueryString());
    }
    
    public static String getRequestUrl(FilterInvocation fi) {
        HttpServletRequest r = fi.getHttpRequest();
        
        return buildRequestUrl(r.getServletPath(),
                               r.getRequestURI(),
                               r.getContextPath(),
                               r.getPathInfo(),
                               r.getQueryString());
    }
    
    public static String getRequestUrl(HttpServletRequest r) {
        return buildRequestUrl(r.getServletPath(),
                               r.getRequestURI(),
                               r.getContextPath(),
                               r.getPathInfo(),
                               r.getQueryString());
    }
    
}
